package model

import (
	"encoding/json"
	"fmt"
	"github.com/smartwalle/alipay/v3"
	"gitlab.local/backend/pkg/utils"
	"net/http"
	"pay/bll/infra/wx"
	"pay/model/entity"
	"strconv"
	"strings"
)

type FeePlanType int

const (
	FeePlanTypeYearlyPlan        FeePlanType = 1 // 包年
	FeePlanTypeYearlyRenewalPlan FeePlanType = 2 // 连续包年，每年自动续费
)

func (a FeePlanType) String() string {
	switch a {
	case FeePlanTypeYearlyPlan:
		return "按年套餐"
	case FeePlanTypeYearlyRenewalPlan:
		return "连续包年"
	}
	return "unknown"
}

// PayChannel 支付渠道
type PayChannel string

const (
	AliPay   PayChannel = "ali"   // 支付宝支付
	WxPay    PayChannel = "wx"    // 微信支付
	ApplePay PayChannel = "apple" // 苹果支付
)

func (c PayChannel) String() string {
	switch c {
	case AliPay:
		return "支付宝"
	case WxPay:
		return "微信"
	case ApplePay:
		return "苹果"
	default:
		return "unknown"
	}
}

// PayOrderStatus 支付订单状态
type PayOrderStatus uint8

const (
	OrderCreated   PayOrderStatus = 0 // 已创建,待支付
	OrderPayed     PayOrderStatus = 1 // 支付成功
	OrderExpired   PayOrderStatus = 2 // 支付超时,被取消
	OrderCanceled  PayOrderStatus = 3 // 用户取消支付
	OrderRefunded  PayOrderStatus = 4 // 已退款
	OrderPayFailed PayOrderStatus = 5 // 支付失败
)

func (s PayOrderStatus) String() string {
	switch s {
	case OrderCreated:
		return "待支付"
	case OrderPayed:
		return "已支付"
	case OrderExpired:
		return "超时取消"
	case OrderCanceled:
		return "用户取消"
	case OrderRefunded:
		return "已退款"
	case OrderPayFailed:
		return "支付失败"
	default:
		return "unknown"
	}
}

type FeePlanOpType int

func (o FeePlanOpType) String() string {

	switch o {
	case 1:
		return "创建"
	case 2:
		return "更新"
	case 3:
		return "删除"
	default:
		return "未知"
	}
}

const (
	FeePlanOpCreate FeePlanOpType = iota + 1
	FeePlanOpUpdate
	FeePlanOpDelete
)

type StatusDetail struct {
	Status alipay.TradeStatus `json:"ali_status"`
}

func (s *StatusDetail) String() json.RawMessage {
	jsonBytes, _ := json.Marshal(s)
	return jsonBytes
}

type FeePlanCreateRequest struct {
	Id        int64           `json:"id"`
	Name      string          `json:"name"`
	Type      int             `json:"type"`
	Enable    int             `json:"enable"`
	Packs     json.RawMessage `json:"packs"`
	CreatedAt int64           `json:"created_at"`
	UpdatedAt int64           `json:"updated_at"`
}

type FeePlanUpdateRequest struct {
	Id        *int64          `json:"id"`
	Name      *string         `json:"name"`
	Type      *int            `json:"type"`
	Enable    *int            `json:"enable"`
	Packs     json.RawMessage `json:"packs"`
	CreatedAt *int64          `json:"created_at"`
	UpdatedAt *int64          `json:"updated_at"`
}
type FeePlanListRequest struct {
	Id        *int64          `json:"id"`
	Ids       []int64         `json:"ids"`
	Name      *string         `json:"name"`
	Type      *int            `json:"type"`
	Enable    *int            `json:"enable"`
	Packs     json.RawMessage `json:"packs"`
	CreatedAt *int64          `json:"created_at"`
	UpdatedAt *int64          `json:"updated_at"`
	Index     int             `json:"index"`
	Size      int             `json:"size"`
}

type Resource struct {
	OriginalType   string `json:"original_type"`
	Algorithm      string `json:"algorithm"`       // 对开启结果数据进行加密的加密算法
	Ciphertext     string `json:"ciphertext"`      // base64 编码后的开启/停用结果数据密文
	AssociatedData string `json:"associated_data"` // 附加数据
	Nonce          string `json:"nonce"`           // 随机字符串，加密用
}

type WxPayNotifyRequest struct {
	wx.ReqHeaders
	wx.NotifyRequest
	RequestBody []byte `json:"request_body"`
}

type AliPayNotifyRequest struct {
	*http.Request
}

type ReceiveSignNotifyRequest struct {
	*http.Request
}

type AppListFeePlanRequest struct {
	BikeId *int64 `json:"ebike_id" binding:"required"` // 车辆id
}

type AppPrePayRequest struct {
	Channel PayChannel `json:"channel" binding:"required,oneof=ali wx apple"` // 支付渠道
	Id      int64      `json:"id"`                                            // fee_plan_group_object的主键ID
	GroupId int64      `json:"group_id" binding:"required"`                   // fee_plan_group_object的主键ID
	EbikeId int64      `json:"ebike_id" binding:"required"`
	PlanId  int64      `json:"plan_id" binding:"required"` // fee_plan_group_object 的detail字段中的pland_id
	No      int        `json:"no" binding:"required"`      // fee_plan_group_object 的detail字段中的id
}

type AppPayResultRequest struct {
	TradeNo string `json:"trade_no"`
}

type AppPayResultResponse entity.FeePlanPaymentOrder

func (a *AppPrePayRequest) String() string {

	b, _ := json.Marshal(a)
	return string(b)
}

type AppPrePayResponse struct {
	TradeNo  string `json:"trade_no"`  // 支付单号
	PrepayId string `json:"prepay_id"` // 预支付id
	Expires  int64  `json:"expires"`   // 支付超时失效时间
}

type AppListFeePlanResponse FeePlanGroupObjectInfo

type FeePlanListResponse struct {
	Total int            `json:"total"`
	List  []*FeePlanInfo `json:"list"`
}
type FeePlanInfoRequest struct {
	Id int64 `json:"id"`
}
type FeePlanInfo struct {
	Id          int64           `json:"id"`
	Name        string          `json:"name"`
	Type        int             `json:"type"`
	FeeTypeName string          `json:"fee_type_name"`
	Content     string          `json:"content"`
	Enable      int             `json:"enable"`
	YearlyMoney int32           `json:"yearly_money,omitempty"`
	Packs       json.RawMessage `json:"packs"`
	CreatedAt   int64           `json:"created_at"`
	UpdatedAt   int64           `json:"updated_at"`
}

type FeePlanDeleteRequest struct {
	Id int64 `json:"id"`
}

type PlanPack struct {
	No     int64       `json:"no"`
	PlanId int64       `json:"plan_id"`
	Years  uint8       `json:"years,omitempty"`
	Money  uint32      `json:"money,omitempty"`
	Type   FeePlanType `json:"type"`
}

func (pk PlanPack) String() string {

	var v string
	if pk.Type == FeePlanTypeYearlyPlan {
		v = fmt.Sprintf("%d年%v元", pk.Years, utils.ShiftLeft(strconv.Itoa(int(pk.Money)), 2, 2))
	}

	if pk.Type == FeePlanTypeYearlyRenewalPlan {
		v = fmt.Sprintf("%v元", utils.ShiftLeft(strconv.Itoa(int(pk.Money)), 2, 2))
	}

	return v
}

type PlanPacks []PlanPack

type PlanPackOption struct {
	PlanId *int64
	Type   *FeePlanType
}

func NewPlanPacks(b json.RawMessage, opts ...*PlanPackOption) PlanPacks {

	if b == nil {
		return nil
	}
	var (
		index = int64(1)
		res   PlanPacks
	)
	_ = json.Unmarshal(b, &res)
	for i, _ := range res {
		if res[i].No == 0 {
			res[i].No = index
			index = index + 1
		}

		if len(opts) > 0 {
			if opts[0].PlanId != nil && res[i].PlanId == 0 {
				res[i].PlanId = *opts[0].PlanId
			}

			if opts[0].Type != nil && res[i].Type == 0 {
				res[i].Type = *opts[0].Type
			}
		}
	}

	return res
}

func (pk PlanPacks) Equal(another PlanPacks) bool {

	var (
		pkMap      = make(map[string]PlanPack)
		anotherMap = make(map[string]PlanPack)
		equal      = true
	)
	for _, v := range pk {
		pkMap[v.String()] = v
	}

	for _, v := range another {
		anotherMap[v.String()] = v
	}

	if len(pkMap) != len(anotherMap) {
		return false
	}

	for k, _ := range pkMap {
		if _, ok := anotherMap[k]; !ok {
			equal = false
			break
		}
	}

	return equal
}

func (pk PlanPacks) Check() error {
	for _, v := range pk {
		if v.Type == FeePlanTypeYearlyPlan {
			if !(v.Money > 0 && v.Years > 0) {
				return fmt.Errorf("当选择套餐类型为%v，必须设置金额和年", FeePlanTypeYearlyPlan.String())
			}
		}

		if v.Type == FeePlanTypeYearlyRenewalPlan {
			if v.Money <= 0 {
				return fmt.Errorf("当选择套餐类型为%v，必须设置金额", FeePlanTypeYearlyRenewalPlan.String())
			}
		}
	}

	return nil
}

func (pk PlanPacks) Bytes() json.RawMessage {
	if len(pk) == 0 {
		return nil
	}
	bb, _ := json.Marshal(pk)
	return bb
}

func (pk PlanPacks) Item(no int) *PlanPack {
	if len(pk) == 0 {
		return nil
	}
	for _, v := range pk {
		if v.No == int64(no) {
			return &v
		}
	}
	return nil
}

func (pk PlanPacks) String() string {

	var contents []string
	for _, v := range pk {
		contents = append(contents, v.String())
	}

	return strings.Join(contents, "；")
}
